home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 201-225 / disk_217 / stevie / edit.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  8KB  |  388 lines

  1. /*
  2.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  3.  *
  4.  * Code Contributions By : Tim Thompson           twitch!tjt
  5.  *                         Tony Andrews           onecom!wldrdg!tony 
  6.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  7.  */
  8.  
  9. #include "stevie.h"
  10.  
  11. /*
  12.  * This flag is used to make auto-indent work right on lines where only a
  13.  * <RETURN> or <ESC> is typed. It is set when an auto-indent is done, and
  14.  * reset when any other editting is done on the line. If an <ESC> or <RETURN>
  15.  * is received, and did_ai is TRUE, the line is truncated. 
  16.  */
  17. bool_t          did_ai = FALSE;
  18.  
  19. void
  20. edit()
  21. {
  22.     char            c;
  23.     bool_t          literal_next_flag = FALSE;
  24.  
  25.     Prenum = 0;
  26.  
  27.     /* position the display and the cursor at the top of the file. */
  28.     *Topchar = *Filemem;
  29.     *Curschar = *Filemem;
  30.     Cursrow = Curscol = 0;
  31.  
  32.     s_refresh(NOT_VALID);
  33.  
  34.     for (;;) {
  35.  
  36.     if (!RedrawingDisabled) {
  37.         /* Figure out where the cursor is based on Curschar. */
  38.         cursupdate(UPDATE_CURSOR);
  39.         windgoto(Cursrow, Curscol);
  40.     }
  41.     c = vgetc();
  42.  
  43.     if (State == NORMAL) {
  44.         /* We're in the normal (non-insert) mode. */
  45.  
  46.         /* Pick up any leading digits and compute 'Prenum' */
  47.         if (isascii(c)) {    /* must disallow special chars from "ascii.h" */
  48.         if ((Prenum > 0 && isdigit(c)) || (isdigit(c) && c != '0')) {
  49.             Prenum = Prenum * 10 + (c - '0');
  50.             continue;
  51.         }
  52.         }
  53.         /* execute the command */
  54.         normal(c);
  55.         Prenum = 0;
  56.  
  57.     } else {
  58.         if (c == CTRL('V') && !literal_next_flag) {
  59.         literal_next_flag = TRUE;
  60.         outchar('^');
  61.         continue;
  62.         }
  63.         if (literal_next_flag) {
  64.         literal_next_flag = FALSE;
  65.         outchar('\b');
  66.         if (c != NL) {
  67.             did_ai = FALSE;
  68.             insertchar(c);
  69.             continue;
  70.         }
  71.         }
  72.         switch (c) {    /* We're in insert mode */
  73.  
  74.           case ESC:    /* an escape ends input mode */
  75.     doESCkey:
  76.         /*
  77.          * If we just did an auto-indent, truncate the line, and put
  78.          * the cursor back. 
  79.          */
  80.         if (did_ai) {
  81.             Curschar->linep->s[0] = NUL;
  82.             Curschar->index = 0;
  83.             did_ai = FALSE;
  84.         }
  85.         set_want_col = TRUE;
  86.  
  87.         /*
  88.          * The cursor should end up on the last inserted character.
  89.          * This is an attempt to match the real 'vi', but it may not
  90.          * be quite right yet. 
  91.          */
  92.         if (Curschar->index != 0) {
  93.             if (gchar(Curschar) == NUL)
  94.             dec(Curschar);
  95.             else if (Insbuffptr != NULL)
  96.             dec(Curschar);
  97.         }
  98.         State = NORMAL;
  99.         msg("");
  100.  
  101.         if (!UndoInProgress) {
  102.             int             n;
  103.             char           *p;
  104.  
  105.             if (last_command == 'o')
  106.             AppendToUndobuff(UNDO_SHIFTJ_STR);
  107.  
  108.             if (Insbuffptr != NULL) {
  109.             if (last_command == 'O')
  110.                 AppendToUndobuff("0");
  111.             AppendToRedobuff(Insbuff);
  112.             AppendToUndoUndobuff(Insbuff);
  113.             n = 0;
  114.             for (p = Insbuff; *p != NUL; p++) {
  115.                 if (*p == NL) {
  116.                 if (n) {
  117.                     AppendNumberToUndobuff(n);
  118.                     AppendToUndobuff("dl");
  119.                     n = 0;
  120.                 }
  121.                 AppendToUndobuff(UNDO_SHIFTJ_STR);
  122.                 } else
  123.                 n++;
  124.             }
  125.             if (n) {
  126.                 AppendNumberToUndobuff(n);
  127.                 AppendToUndobuff("dl");
  128.             }
  129.             }
  130.             if (last_command == 'c') {
  131.             AppendToUndobuff(mkstr(last_command_char));
  132.             AppendToUndobuff(Yankbuff);
  133.             AppendToUndobuff(ESC_STR);
  134.             }
  135.             AppendToRedobuff(ESC_STR);
  136.             AppendToUndoUndobuff(ESC_STR);
  137.             if (last_command == 'O')
  138.             AppendToUndobuff(UNDO_SHIFTJ_STR);
  139.         }
  140.         break;
  141.  
  142.           case CTRL('D'):
  143.         /*
  144.          * Control-D is treated as a backspace in insert mode to make
  145.          * auto-indent easier. This isn't completely compatible with
  146.          * vi, but it's a lot easier than doing it exactly right, and
  147.          * the difference isn't very noticeable. 
  148.          */
  149.           case BS:
  150.         /* can't backup past starting point */
  151.         if (Curschar->linep == Insstart->linep &&
  152.             Curschar->index <= Insstart->index) {
  153.             beep();
  154.             break;
  155.         }
  156.         /* can't backup to a previous line */
  157.         if (Curschar->linep != Insstart->linep &&
  158.             Curschar->index <= 0) {
  159.             beep();
  160.             break;
  161.         }
  162.         did_ai = FALSE;
  163.         dec(Curschar);
  164.         delchar(TRUE, FALSE);
  165.         /*
  166.          * It's a little strange to put backspaces into the redo
  167.          * buffer, but it makes auto-indent a lot easier to deal
  168.          * with. 
  169.          */
  170.         AppendToInsbuff(BS_STR);
  171.         if (!RedrawingDisabled)    /* screen will be fixed later */
  172.             S_LINE_NOT_VALID;
  173.         break;
  174.  
  175.           case CR:
  176.           case NL:
  177.         AppendToInsbuff(NL_STR);
  178.         if (!OpenForward(!RedrawingDisabled))
  179.             goto doESCkey;    /* out of memory */
  180.         break;
  181.  
  182.           default:
  183.         did_ai = FALSE;
  184.         insertchar(c);
  185.         break;
  186.         }
  187.     }
  188.     }
  189. }
  190.  
  191. /*
  192.  * Special characters in this context are those that need processing other
  193.  * than the simple insertion that can be performed here. This includes ESC
  194.  * which terminates the insert, and CR/NL which need special processing to
  195.  * open up a new line. This routine tries to optimize insertions performed by
  196.  * the "redo", "undo" or "put" commands, so it needs to know when it should
  197.  * stop and defer processing to the "normal" mechanism. 
  198.  */
  199. #define ISSPECIAL(c)    ((c) == BS || (c) == NL || (c) == CR || (c) == ESC)
  200.  
  201. void
  202. insertchar(c)
  203.     char            c;
  204. {
  205.     if (anyinput()) {        /* If there's any pending input, grab up to
  206.                  * MAX_COLUMNS at once. */
  207.     char            p[MAX_COLUMNS + 1];
  208.     int             i;
  209.  
  210.     p[0] = c;
  211.     i = 1;
  212.     c = vpeekc();
  213.     while (!ISSPECIAL(c) && anyinput() && (i < MAX_COLUMNS)) {
  214.         p[i++] = vgetc();
  215.         c = vpeekc();
  216.     }
  217.     p[i] = '\0';
  218.     insstr(p);
  219.     AppendToInsbuff(p);
  220.     } else {
  221.     inschar(c);
  222.     AppendToInsbuff(mkstr(c));
  223.     }
  224.  
  225.     if (!RedrawingDisabled)    /* screen will be fixed later */
  226.     S_LINE_NOT_VALID;
  227. }
  228.  
  229. void
  230. getout(r)
  231.     int             r;
  232. {
  233.     windgoto(Rows - 1, 0);
  234.     outchar('\r');
  235.     outchar('\n');
  236.     windexit(r);
  237. }
  238.  
  239. void
  240. scrolldown(nlines)
  241.     int             nlines;
  242. {
  243.     register LPtr  *p;
  244.  
  245.     S_MUST_UPDATE_BOTCHAR;
  246.     S_CHECK_TOPCHAR_AND_BOTCHAR;
  247.  
  248.     /* Scroll up 'nlines' lines. */
  249.     while (nlines--) {
  250.     p = prevline(Topchar);
  251.     if (p == NULL)
  252.         break;
  253.     Topchar->linep = p->linep;
  254.     }
  255.     /*
  256.      * The calling routine must make sure that Curschar is in the correct
  257.      * place with relation to Botchar.
  258.      */
  259. }
  260.  
  261. void
  262. scrollup(nlines)
  263.     int             nlines;
  264. {
  265.     register LPtr  *p;
  266.  
  267.     S_MUST_UPDATE_BOTCHAR;
  268.     S_CHECK_TOPCHAR_AND_BOTCHAR;
  269.  
  270.     /* Scroll down 'nlines' lines. */
  271.     while (nlines--) {
  272.     p = nextline(Topchar);
  273.     if (p == NULL)
  274.         break;
  275.     Topchar->linep = p->linep;
  276.     }
  277.     /*
  278.      * The calling routine must make sure that Curschar is in the correct
  279.      * place with relation to Topchar.
  280.      */
  281. }
  282.  
  283. /*
  284.  * oneright oneleft onedown oneup 
  285.  *
  286.  * Move one char {right,left,down,up}.  Return TRUE when sucessful, FALSE when
  287.  * we hit a boundary (of a line, or the file). 
  288.  */
  289.  
  290. bool_t
  291. oneright()
  292. {
  293.     set_want_col = TRUE;
  294.  
  295.     switch (inc(Curschar)) {
  296.  
  297.       case 0:
  298.     return TRUE;
  299.  
  300.       case 1:
  301.     dec(Curschar);        /* crossed a line, so back up */
  302.     /* FALLTHROUGH */
  303.       case -1:
  304.     return FALSE;
  305.     }
  306.  
  307.     return FALSE;        /* PARANOIA: should never reach here */
  308. }
  309.  
  310. bool_t
  311. oneleft()
  312. {
  313.     set_want_col = TRUE;
  314.  
  315.     switch (dec(Curschar)) {
  316.  
  317.       case 0:
  318.     return TRUE;
  319.  
  320.       case 1:
  321.     inc(Curschar);        /* crossed a line, so back up */
  322.     /* FALLTHROUGH */
  323.       case -1:
  324.     return FALSE;
  325.     }
  326.  
  327.     return FALSE;        /* PARANOIA: should never reach here */
  328. }
  329.  
  330. void
  331. beginline(flag)
  332.     bool_t          flag;
  333. {
  334.     while (oneleft());
  335.     if (flag) {
  336.     while (isspace(gchar(Curschar)) && oneright());
  337.     }
  338.     set_want_col = TRUE;
  339. }
  340.  
  341. bool_t
  342. oneup(n)
  343.     register int    n;
  344. {
  345.     register int    k;
  346.  
  347.     S_CHECK_TOPCHAR_AND_BOTCHAR;
  348.  
  349.     for (k = 0; k < n; k++) {
  350.     if (Curschar->linep->prev == Filetop->linep) {
  351.         if (k > 0)
  352.         break;
  353.         else
  354.         return FALSE;
  355.     }
  356.     Curschar->linep = Curschar->linep->prev;
  357.     }
  358.  
  359.     /* try to advance to the column we want to be at */
  360.     Curschar->index = 0;
  361.     coladvance(Curschar, Curswant);
  362.     return TRUE;
  363. }
  364.  
  365. bool_t
  366. onedown(n)
  367.     register int    n;
  368. {
  369.     register int    k;
  370.  
  371.     S_CHECK_TOPCHAR_AND_BOTCHAR;
  372.  
  373.     for (k = 0; k < n; k++) {
  374.     if (Curschar->linep->next == Fileend->linep) {
  375.         if (k > 0)
  376.         break;
  377.         else
  378.         return FALSE;
  379.     }
  380.     Curschar->linep = Curschar->linep->next;
  381.     }
  382.  
  383.     /* try to advance to the column we want to be at */
  384.     Curschar->index = 0;
  385.     coladvance(Curschar, Curswant);
  386.     return TRUE;
  387. }
  388.